{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "710dc4f0-1c88-4386-9e9d-fec3de6bb774",
   "metadata": {},
   "source": [
    "# How to create branches for parallel node execution\n",
    "\n",
    "LangGraph natively supports fan-out and fan-in using either regular edges or [conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.MessageGraph.add_conditional_edges).\n",
    "\n",
    "This lets you run nodes in parallel to speed up your total graph execution.\n",
    "\n",
    "Below are some examples showing how to add create branching dataflows that work for you. "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "bb54e2d0",
   "metadata": {},
   "outputs": [],
   "source": [
    "%%capture --no-stderr\n",
    "%pip install -U langgraph"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d6c05fc4-ecd8-483f-a9fd-b1a055f922d9",
   "metadata": {},
   "source": [
    "## Parallel node fan-out and fan-in"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "09372b8b-edea-4b9d-9ec3-3d93ce1ba819",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import Annotated, Any\n",
    "\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import StateGraph\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "\n",
    "\n",
    "class ReturnNodeValue:\n",
    "    def __init__(self, node_secret: str):\n",
    "        self._value = node_secret\n",
    "\n",
    "    def __call__(self, state: State) -> Any:\n",
    "        print(f\"Adding {self._value} to {state['aggregate']}\")\n",
    "        return {\"aggregate\": [self._value]}\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.set_entry_point(\"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"d\")\n",
    "builder.add_edge(\"c\", \"d\")\n",
    "builder.set_finish_point(\"d\")\n",
    "graph = builder.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "66f52a20",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAGCAIIDASIAAhEBAxEB/8QAHQABAAIDAAMBAAAAAAAAAAAAAAYHBAUIAgMJAf/EAE8QAAEDAwICBQYICAwFBQAAAAEAAgMEBREGBxIhCBMxQVUUFiJRlNEXMmF0gZO04QkVIzhCcXWyJDQ1NjdSYnJ2kbGzGEN3gtIzVpWiwf/EABoBAQADAQEBAAAAAAAAAAAAAAADBAUCAQb/xAA4EQACAQICBAwDCQEBAAAAAAAAAQIDEQQhEhUxoQUTFEFRUmFxkbHB0VPh8CIyMzRiY3KB8ULC/9oADAMBAAIRAxEAPwD6poiIDxe9sbHOc4Na0ZLicABa3zqsvjFB7Sz3r81V/Ne8fM5v3CqusNgtj7HbnOt1I5xpoySYG5Poj5FDXr08LTU5pu7tkXcPh+PvnaxaXnVZfGKD2lnvTzqsvjFB7Sz3qu/N61+G0f1DPcnm9a/DaP6hnuWfrXD9SXii5q79W4sTzqsvjFB7Sz3p51WXxig9pZ71Xfm9a/DaP6hnuTzetfhtH9Qz3JrXD9SXihq79W4sTzqsvjFB7Sz3p51WXxig9pZ71Xfm9a/DaP6hnuTzetfhtH9Qz3JrXD9SXihq79W4sTzqsvjFB7Sz3p51WXxig9pZ71Xfm9a/DaP6hnuTzetfhtH9Qz3JrXD9SXihq79W4sTzqsvjFB7Sz3rNo6+muMRlpKiKqiB4S+F4eM+rIVXeb1r8No/qGe5bvaSnipYdTxQxshibdzhkbQ0D+DU/YAruGxdLF6SgmmlfO3Sl6lbEYTiIaV7k9REVkzwiIgCIiA1Wqv5r3j5nN+4VXmn/AOQbb82i/cCsPVX817x8zm/cKrzT/wDINt+bRfuBZPCv5eHe/JGzwd/0bBERfKm0Qik3o0fcNR19ipLq+qudCZmTxwUU8jA+JpdLG2QMLHvaAcsa4uzyxlR7bTpE2DXW3tXqmujqrLDRcbqtk1FU9XG3rnxx8EjomiYkMGRHkgnBAKi+lfxrYd7/ACLSVn1Pb9N3C4V0+oaO80BZbWP4XFtXSTnvllDTwNcQQ8ktYQtDpy4az0rsTXaQtVh1FbdTWatkbVVUFuLuspH3BzpZKKRwLJpOokLmgZOQeWQFe4qFrLs5++/MU+Mle77ebuLjtu+Oibtpa+aipr1m12RpfcnSUk8c1KOHiy+FzBIMjmPR592VGtZ9JnTWnbZZq+3MrbxS194p7Y6oit1X1YZIculicISJsN5tDM8RPInGFTlz0pdKm0b2NtWn9Z1FJfdLUrbdLfoameqrZYjO17R1nE9rsyN4Y3BrsZIbwq5t7bLXt0No+rtlpqri3T99tlyqKC3wmSfyeF4DxHGObnNBzwjnyXvFUoyS237exeo4ypKLfR7lpWq5wXq2UtfS9b5NVRNmj66F8L+FwyOJjwHNOD2OAI7wsta+w3lmoLRTXGOlrKJlQ3iEFfTugnZzI9ONwBaeXYVsFReTLazQWdtX2ap/bB+y06wVnbV9mqf2wfstOt/gf79X+P8A6iZ2P/CXeTpERfQHzwREQBERAarVX817x8zm/cKrqyRMn05QRyND430kbXNcMggsGQVadbSR3CiqKWYExTxuieAcHhIwf9VDYdpLdTwsiju16ZGxoa1oreQA5AdirYrDLFUlDSs07mhhcRGhfS5ysR0f9swQRoDTYI7xa4f/ABT/AIftsv8A2Bpv/wCLh/8AFWj8FVD4xe/bfuT4KqHxi9+2/cs7VlT43mXOWUOruRqYII6aCOGFjYoo2hjGMGA1oGAAPUvYtl8FVD4xe/bfuT4KqHxi9+2/co9T/urwZJrCl0M1qKtOinS1u7uylp1PqG93SS61NVWRSOp6jq2cMdTJGzDQP6rQrd+Cqh8Yvftv3Jqf91eDGsKXQyvb7s7oXVF1nud40fZLpcZ+HrauroIpJZMNDRxOLSTgAD9QCwXbBbaPDQ7QWnHBow0G2Q8hnOB6PrJ/zVofBVQ+MXv237k+Cqh8Yvftv3KRcFzWSreZxy2g/wDnciM6c0vZ9IWxtusdspLRQNcXtpaKFsUYce08LQBkqRbV9mqf2wfstOvZ8FVD4xe/bfuW90vpWk0lS1MFJJUTeUzmolkqpOse55a1vb+pjR9Cu4PB8kc5Oek5K3P0p+hWxOKhWp6EUblERXTLCIiAIiIAiIgCIiAIiIDnfoCfmx2D59cvtsy6IXO/QE/NjsHz65fbZl0QgCIiAIiIAiIgCIiAIiIAiIgCIiAIiIDnfoCfmx2D59cvtsy6IXO/QE/NjsHz65fbZl0QgCIiAIiIAiIgCIiAIiIAiIgCIiALiL8J3sW7V2gbfuLbIA+56dHk1fwj0pKJ7/RPrPVyOzj1SvJ7F2zUVEVJBJPPIyGGJpe+SRwa1jQMkknsAHeq41RrNmrrTcLTS6cZebLXwSUs8lyqPJoKiJ7S14a0Me8tIJGS1ue0csEyRpynmvbzJIU51HaKufM/8HfsjJulvnSX+rif+ItIujucsg5B1UHZpo8+vjaX/qiIPavr2ubOjloF/Rp0O7TVus8d4hnq5KyquMVaG1Ez3YABY6NrcNY1rRh4BwTgZK6AsGo6DU1Gaign6wMdwSxOHDJC/vY9h5tPYcHuIIyCCvZU5RV9q7Hf/DqdKdP7yNmiIoiEIiIAiIgCIiAIiIAiIgCIiArTVlw859QT0DvTtNre0OiyC2oqcB3pjvbGCzAPLjJOMsaR4LV6deZaaulfjrH3KuL+Xf5VKMfRjH0LTbrakZpPQVzuLry+wyNDI4a2Kj8rlEj3taxscP8AzHuJDWj1uBPIKTEZTdPmjl9d59LRiqVJWJasKsnnsc4vdAxzqulbmWFhx5VCMl0Tu4nBJaT2OxzwXA1HsLrvVV51Xq/TOqX3Gofa4aKspKi8UVNSVjo5xKC2RlO50eAYsgjB9IgjkrpUUJunK539mrCzWTLIo6yG4UcFVTyCWnnjbLHI3sc1wyCP1gr3KJ7Uvc/byyA/FZCYmY5Dga4tZj5OEBSxS1Y6E5QXM2fMNWbQREUZ4EREAREQBERAEREARFoNea8sW2ek7jqTUlwitlnoI+smnlP+TWjtc4nADRzJIAQELrqJ1g1TcqGTIgrJHV9I9x5ODzmZg+VryXH5JG/KtJrvQ9v3D03NZrk+ohhdJFPHUUcnVz080bxJHJG7Bw5rmgjII5cwQp/aKm3bvaCtF2lt1xtUNfCyupoq2Pyeto3Fp4XYBPA/BI7SCHEHLXEGO1lj1NZZDGbZ+P6dvxaqhljilcP7cUjmgH18LiD2gDPCJpR456UXnz3y/vPebOHxMHDQqEJ0VtJQ6J1PcdQx3q9Xe63Kljpa2a6VLJROI3OMby1rGhpaHOaAzhbgn0Sealt2qZ4KXq6NgmuFQ7qKSEnHWSkHhH6hguJ7mtce5ecEOoa94bS6Yq42k4M1fPFAwfQHOf8A/X/NTDS2i22WU19fOLhd3tLeu4eGOBp7WRN/RB5ZJJc7HM4AA8jS4t6VS3de9/DYS1MTTpRtB3Zt9P2ePT1it9sieZI6OnZAJHfGfwtA4j8pxk/KVsFAtvd6dO7j6i1Np+hNVb9Qadq3U1darlD1NQGg+hO1uTxRPGC1w7iMgZGZ6uJNybk9rMEIiLkBERAEREAREQBEWl1lrGzbf6YuGodQ3CG12egiM1RVTnDWjuAHaSTgBoySSAASUB4621tZNudLXHUeorhFa7PQRmWepmPIDsAA7XOJwA0ZJJAAyVz3oDRl76UWrbduVuFb5rZoa3yCo0lo2qHOU/o19Y3sc8jmxh5AH1c3+jQ+kbz0tdV2/cPXlvmte2tul8o0rpCqGDXO/Rr6xvYcjmxhyMHvaSZOpuxAfqIiAIiICmt+NjKvW9Xb9a6Krmad3PsTSbbdMYiq4+11JVAfHifzHPm0nI7SDstid9aTd+2V1FXUL9Oa3sj/ACa+6cqj+Wo5v6zf68Tu1rxyIKtNUjv3sZcdU3Oh1/t/Vx2HdGyMxSVbuUNzg7XUdUP0mO7AT8U947QBdyKrdht+LdvTZKuOWkksGr7PJ5LfNOVfKooJxyPI83RuIPC/v7ORBCtJAEREAREQBERAYV6vFHp2zV91uE3k9BQ08lVUTFpdwRsaXOdgZJwATyXLejdM3bplaooNea0oprZtLbZuv0zpSpGHXV4yBXVbewt/qM5gj1tyZL73w/oV3A/w/cPs0i0XRY/Nu2z/AMP0f+01AWk1oa0NaAABgAdy/URAEREAREQBERAURv5sTdb1fKTcvbWpisu6Nnj4WOd6NPeacdtJUjIBBAw1x7OQyMNcyX7Db0Um9+ipLsy3VNku9vqn2y8WisYWyUNbGB1kRJA4gOIEH1HmAQQLIXO3RC/lnfb/AKj3T92JAdEoiIAiIgCIiA4y6a3TBuWzddfdvKvQPl1Df7LLHRX1t3MYcyaJ0TyYuoPpMfxejx8wGnI4uWm6C/S/rtwajSG01JoN0dNZrOI6y/tuvGI44IuESGHqR8d/Vsxx8uPOThWX+EB2Si3b2NqrhSxRnUOmi640Lj8eWPh/Lwt7zxMAcAOZdG0d60n4OLZCLbXZ5+pq6IN1FqhzaiRrvjwUrc9RGR3F2XSHs+O0EZavbO1wdbIiLwBERAEREAREQFH9KzpGXLo0aUtOooNG+ddsqqo0lVILj5IaV5bxRkjqZOIO4ZBnlgtaOfFy4s6PvT0r9Lat1TbLVts6/wBz1zqya601My9dSYZKksY2DPk7uPBaPT9HOewYX0W3Z24tu7u3N/0hdmg0l1pXQ9YW8Rhk7Y5QPWx4a4fK1cG/g7+jDX2jdzVOqtVUXVS6RqZbTRRu5tfWHLZJWn9JrGHkcYPWgj4q9sD6PoiLwBERAFD9XasqIKx1ntD2srg1r6mrczjZSsdnAA7HSkDIB5NGHOBBa18sqZ2UtPLNIcRxtL3H5AMlVBph0lVaIq+fBq7j/DZ3DPN8npY59wBDR8jQFLG0Yuo+bJd5dwtFVZ/a2I/PNa2zTmorKcXSsPxqq4fwiU/qL88I/stwB3AYXkdL2xswnp6RlBVNyW1NF+QlaT/aZg/QeSh27+6h2urNGyTdQy2XW7GhrZZIZJXsj8nmkBjazmXl8bBjDs5IxnCkmiNwdP7jWuW4aduTLjTQyugmAY+OSGQdrJI3gPY7mOTgDzXHH1b30n4m4tD7hOtJ6rqWVsVnu8pqJpAfJbgWtb1+BkseGgASYBPIAOAOAMEKaqn9R08s9mqXU7gysgb5RTSH9CZnpRu/VxAZHeMjvVqWe5R3m0UNwhBEVXAydgPcHNDh/qu5WnBVF3P67fQxMXRVKScdjMxERRFEIiIAtLqnU0emqBsghNXWTu6qmpGu4TK/5Tz4Wgc3OwcAcgTgHdKr77VfjXXt0e7Dm2uKOhiHP0HPa2aQ/wDcHQj/ALApaaWcnsSv6ebLFClxtRRew19wtDtSSGfUMgusruymcCKWIf1WRZwflc7Lj68YA9MmjbFIWOFoo4nxjDJIYWxvYP7Lm4I+grbSSMhjdJI5rGNBc5zjgADtJKhmkd5tHa8vDrZYbubjUhj5GuZSTthla0gOdHM5gjkAJHNjj2rnlFXmk13ZH0KjCCUVZE8sWqavTE8dNcqh9bZpHiNlXM4umpCThokcfjx93GfSbyLi4EubY6q2pp4qunlgmYJIZWlj2O7HNIwQfoUr22uMtx0fR+USddUUz5aOSQkkuMMjo+Ik88kMB+ldt8ZDTe1be2/+Z/6ZGMoxptTjzknREUJmmNcqT8YW6qpScdfE+LPqyCP/ANVS6UkdJpq2B7XMlZTsikY4YLXtHC4H9TgQrjVcaqsj9L3GrukMZfZqt/XVIjaXOpZj8aQgf8t3IuP6LsuOWucWTRWnB01t2r2+ug0MHVUJuMucp/fZldTXnbe70lnuV5p7Vf3VVXHa6V1RLHF5JUML+EcyMvb8pzgAkgHx2coK+67g7ha1ms1dYLXfnUEFHSXODyepl8nie1874jzZxF4aA7DiIwSByVsxTR1ETJYntkjeA5r2HIcD2EFfr3tjY573BjGjJc44AHrKq9hs6H2tK/1axhX2tFtstfVEF3UwPfwtGSSGnAA7yezCsfStqfYtL2e2yYL6Ojhp3Y9bGBp/0UH03aDrKtpawhrrBTSNnZLk4rJWkOZw9xjacO4uxxAxyBzZqtNcXDQe2936epj42qpyUY8wREUJnBERAFVddTuotdamieCPKZYK5mRyLXQMi5f90DlaiieuNM1FyNPdbbG2W6UbXMELnBoqYXEF0eTyDstBaTyByCQHEiam76UOlW3p+haw1RUqib2Fa7p6crdYbaarsVtlENwuVrqaSne53CBI+JzW5PcMkZKjO0Wvn3C2WXTc2i9R6dq6GgZBUeXW0w0dO6JjW8DJs8MgJHolmQQOeFYtBcoLiyQxFzZIndXNDI0tkhf/AFXtPNp5g4PcQewhZKrSi4vRksz6C13pJhb7aqAs0eyoIcBWVVTVN4hg8D5nlh+lvCfpUWp6KfWNTLbKAvbSNcY664N5Mib2Ojjd3ykZHLkzmXcw1rrUpaaKipoqeCNsMETBHHGwYDWgYAA9QCs2dOnova7eC97mVjqqdoI9qIihMoIiICrd3dGWqxbe6w1DaYZbRdKK1VldFJQTvgjMzIXva50bSGOPEASS3J5+srVdH7TdDrXZ/RGqL+2W8Xe5WqnrZ3Vkz5IutfGHOIiJ4Bz7OXJTHfD+hXcD/D9w+zSLRdFj827bP/D9H/tNU/H1esyTjJ2tfItNERQEYREQBERAEREBo7/omy6mnZPcKESVLG8DamGR8Mwb2gdYwtdjJPLPefWqJ6O9vj3Eum6cOopqu6w6e1lXWW3xTVk3AyliDCxrmhwEh9I+k8E/Kuklzt0Qv5Z32/6j3T92JTKtVirKT8TtTklZM6Do6Ont1LFTUsEdNTRNDI4YWBjGNHYAByAXuRFE3fNnAREXgCIiAhO+H9Cu4H+H7h9mkWi6LH5t22f+H6P/AGmqc6202NZaMv8AYDOaUXW31FCZw3i6vrY3M4sZGccWcZHYqE6MG5dXoeaj2L19RxWLWenqRsNqmY4+S3yhYMMmp3HteGt9JnbyJwMOawDpVERAEREAREQBERAFzt0Qv5Z32/6j3T92JWHvlvjZNi9JNulyZLcbpWSeS2myUnpVVyqTgNijaAT2kZdg4B7yQDG+ivtrqXQWkdRXTWIpqfU2rr5UajrbdR5MdC+cM/IBxJ4i3h5nsBOMnGSBdSIiAIiIAiIgCrXfXYyz746XioquaW0323yeVWa/0fo1VtqRgtkY4EHGQ3ibkZwOwhpFlIgKG2I3wvNXqGo2v3PhitO5trj445mejTX2mGcVVMcAEkAlzBjBBIAw5rLwkuVJFcYKB9VCyvniknipXSASyRsLGyPa3OS1pkjBI5Avbn4wXNPT8vGg9N7UQXfUdbNbdZ0krptI1NseG3Flc3BBjPaIQeDrSfRA4cemYweBdoulDqmu6V2ktxNaXuS4TPqY7dVyyERwwUcgMTmtY0BrWMEhk4QBlwLjlxJIH2ZREQBERAFAN6d57Fsfo917vHW1dVNIKa3WmkHFU3GpdyZDE0cyScZOOQ5+oHiH8KPvDXUWtdEaQs1xqaGezt/H0stJK6N0dSXFtO8OaQWyRhj3AjmOt5Lc9B3d6y9IDduovm5l7ddd1KCmbBp+kq4mRUbKZsY66SlY30fKSQ98gwDwnLBwh4YB0Dshspfbrq127W64jq9f1cfDbbS08VNp2mOcQxDmDKQfSf8AKQDzcXdBoiAIiIAiIgCIiAIiIDRaz0Jp3cSyutGp7JQ362ud1nk1wgbKxr8EB7cj0XAOcA4YIycFcmbm/gutvNSiWo0fdbjo6rPNlO8+W0g+TheRIMnv6w/qXaCIDSWKB+kdG22nvV3ZWy22hiirLrO0QNmdHGA+ZwLjwcRBdjiOM9p7VG63cmvrHkWSydZT91XdJjTB/wArIw1zyP74Z/pnC1JdXal1FPT8RNqtUgjEYd6M9SMOc9w7xHyDQf0uI4JawjxUzcaWTV35fM1sPhFKOnU5zKg19qKmcDV2ahq4sji8iq3MkA78Ne3B+lwUv09qah1NSvlo3va+M8M1PPGY5YXepzTzHyHsPaCRzVdi70JurrWK2nNzbAKk0XWt64RFxaJODOeEuBHFjGQQvytkqbXMy729rnV9I0nqWu4RUx9rondxzz4c9jsH15RnGo9FpJ9PuSVcHBxvT2lPbgfg9bXvBvVqLXWtdY11VSXGdjoLZbKZtO6OJjGMYx0r3PzgN4TwtGcZyCcC8trejltxsyyJ2k9J0FvrY2louMjOurCCMO/LPy8A+oED5FYFuuEF2t9LXUsglpamJs0Ug7HMcAWn6QQslRNNOzMUIiLwBERAEREAREQBERAEREBTWlXultLpX/8Aqy1VTJJ/fM7y7Py5JUY3r1tc9E6RpTZBAL3d7nSWahmqm8UMEtRKIxK8d4aCTjvIA71Np6F2ntSXG2SAtiqJZK+jcTyfG93FI0f3JHnI7g9nrwtPrzQ1q3G0xVWK8MlNJOWPbLTyGOaGRjg5kkbxza9rgCD8neMhd4j8WUuZ5+J9NB6dJOHQVToSyXuwdJe5U991JLqiqOj6d7KyajipnNb5ZKODhiAaRkOIOM4ODnGVeygOitnqTR2q59Ryaiv+obtNb2Wx015qY5fyLZDIMBkbMHLj2cj6s5Kmd1q5aSkPk0QqK2UiKmgzjrZT8Vv6u8nuAJ7lDGLnJRXOdQWhFtkq2me5+grc0/FjfURR/wBxk8jWY+ThAUvWs0zZWac0/brWyQyikgZEZXdsjgPSeflJyT+tbNWK0lOpKS2Ns+Zk7ybQREURyEREAREQBERAEREAREQGr1Dp2l1JQinqC+KRjusgqYcCWB/YHsJBGcEgggggkEEEhQGttOpLK8smtJvUA+LVWx7GuI9b4pHNLT8jXP8Ao7rSRSxnZaMldfXR/hYpV50fuso3Q2sjufY4LxpO2VFztk8j42V072QQZY4sfkkl3JzSOTT2KydLaMdapxcLnNFXXXhLWOjj4YqZp7WxgknJ7C483Y7Gj0VUHQE/NjsHz65fbZl0QjmkrQjbz+u46qYmpVVnsCIiiKoREQBERAEREAREQBERAEREAREQHO/QE/NjsHz65fbZl0Qud+gJ+bHYPn1y+2zLohAEREAREQBERAEREAREQBERAEREARFzd0sulzcui7cbDxaD85bRdon8FwbdjS9XOw+lE5nUP/RcxwPEM5cMeiSQMnoCfmx2D59cvtsy6IXzd6D/AEyK+h8zdnrdoF11mq7lN1l1bduDqYZZ3zSymLqTkRsc444xxcHdlfSJAEREAREQBERAEREAREQBYdbebfbZGx1ddTUsjhxBs0zWEj14JWYqs1hb6Wv3MqBU00NQG2im4etjDsflqjsyurxjGU5bEr70vUr4issPSlVavb3sT/zqsvjFB7Sz3p51WXxig9pZ71Xfm9a/DaP6hnuTzetfhtH9Qz3Kly2h1XuMPXcPhvx+RYnnVZfGKD2lnvVS9KXb7T+/ey980yLnbDdms8stUr6mP8nVxglnPPIOBdGT3B5W283rX4bR/UM9yeb1r8No/qGe5OW0Oq9w13D4b8fkcsfgztn6HRlrve4WpZILfea1zrZbqatkbFJFA1w62Thccgve0NGQCBG7ucu6/Oqy+MUHtLPeq783rX4bR/UM9yeb1r8No/qGe5OW0Oq9w13D4b8fkWJ51WXxig9pZ7086rL4xQe0s96rvzetfhtH9Qz3J5vWvw2j+oZ7k5bQ6r3DXcPhvx+RY0epbRNIyOO60T5HkNa1tQwkk9gAytkqU1DZrfS0tFLDQ00UrblQ4eyFrSP4VF2EBXWrcJQq01Uhfa1n2W9zXwmKWLpuolbO3l7hERC6EREAREQBVpqb+kyq/ZFN/vVCstVpqb+kyq/ZFN/vVC5qfgVe71Rm8JflKn9eaPNERfMnwJp9V6vs+h7NJdb5Xx2+hY5rOseC4ue44axjWgue4nsa0EnuCjMO++hJdOVl9OoI4LbRVMNJVvqYJYZKaWVzWxiWN7A+MOLh6TmgYyc4BKi/SS0ncr5T6Nu9HRXa60FivHldwoLFUyQVr4XQyRGSF0bmvL2F4PC0gkFwUIv+iLfdtC3K66a01rNtzrL7ZYqh2pDWT1dTBT1kUnG1k73yNjYHyZJDcYcezmp4wi0my/So0pRi5N3b7Ms/bMu/Te7GlNV093moLqGNtDBJXtroJaN9NGWlwke2ZrHBha1xD8cJAODyUNsPSFtOuN1tO6c0vVRXG1Vttrayqnlo6iGQGN0IiMRkDQ6N3HJ6QDgeEYIwcw7fPbzUWstXbiwWa21Ewr9G2+KF5YWQ1c0VdPK+nEhHDxuj9HGeQkGcArc2XUNVr7fDQ12pdI6ksVtt1kuUFQ+72qSljhke6m4YskYz6DsEcjj0ScHHShG1/rYdKlTUXJZ5Pn2ZX/vPZs2F8IiKsZxqNUfxCk/aND9riVvqoNUfxCk/aND9riVvr6HCflV/KXlE+z4G/LP+T8kERFOboREQBERAFWmpv6TKr9kU3+9UKy1GdQ6AoNRXYXKWqr6SqEDacuo6jqw5jXOcARg973f5r3RU4Tpt2urb0/Qq4qi8RRlSTs37lcap200lriqhqdQ6atV7qIWdXHLcKOOZzG5zwguBwMnOFpf+H/bPAHmDpzA54/FkOP3VaPwVUPjF79t+5PgqofGL37b9yoLA22VdzPn1wTiErKot5DtKaA0zoUVQ05YLbYhVcJnFvpWQ9bw54eLhAzjidjPrK362XwVUPjF79t+5PgqofGL37b9y8eAT21NzOHwNWk7ua3mtWBfLFbtTWqotl2oae526oAE1LVxCSOQAgjiaeR5gH6FIfgqofGL37b9yfBVQ+MXv237l5q9fEXgwuBayzU1vKvZsDtpGct0DpxpwRkWyEciMEfF9S91v2N27tNfTV1FofT9JWU0rZoJ4bdE18b2kFrmkNyCCAQR6lZXwVUPjF79t+5PgqofGL37b9y65D+7uZJqrE/F8yLao/iFJ+0aH7XErfUJG09sMsD5bjdqhsM0c4jmq8sLmPD25GOY4mgqbK7TpqjRVNO+bfil7GxgcLLCUnTk7533L2CIi9NEIiIAiIgCIiAIiIAiIgCIiAIiIAiIgCIiAIiID/9k=",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "38846b01",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm B to [\"I'm A\"]\n",
      "Adding I'm C to [\"I'm A\"]\n",
      "Adding I'm D to [\"I'm A\", \"I'm B\", \"I'm C\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", \"I'm B\", \"I'm C\", \"I'm D\"]}"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": []}, {\"configurable\": {\"thread_id\": \"foo\"}})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c392b3d2",
   "metadata": {},
   "source": [
    "<details class=\"note\"> <summary>Exception handling?</summary>\n",
    " <p>LangGraph executes nodes within <a href=\"https://langchain-ai.github.io/langgraph/concepts/#core-design\">\"supersteps\"</a>, meaning that while parallel branches are executed in parallel, the entire superstep is <b>transactional</b>. If any of these branches raises an exception, <b>none</b> of the updates are applied to the state (the entire superstep errors).<br><br>\n",
    " If you have error-prone (perhaps want to handle flakey API calls), LangGraph provides two ways to address this:<br>\n",
    " <ol>\n",
    "  <li>You can write regular python code within your node to catch and handle exceptions.</li>\n",
    "  <li>You can set a <b><a href=\"https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.graph.CompiledGraph.retry_policy\">retry_policy</a></b> to direct the graph to retry nodes that raise certain types of exceptions. Only failing branches are retried, so you needn't worry about performing redundant work.</li>\n",
    "</ol></p>\n",
    "Together, these let you perform parallel execution and fully control exception handling.\n",
    "</details>"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "08d8162e-1785-4ae1-993f-6d2ed48c22ae",
   "metadata": {},
   "source": [
    "## Parallel node fan-out and fan-in with extra steps\n",
    "\n",
    "The above example showed how to fan-out and fan-in when each path was only one step. But what if one path had more than one step?"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "259a7704-5aa0-4e4c-aeef-cca04e8be0ff",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import Annotated\n",
    "\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import StateGraph\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.set_entry_point(\"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"b2\", ReturnNodeValue(\"I'm B2\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"b2\")\n",
    "builder.add_edge([\"b2\", \"c\"], \"d\")\n",
    "builder.set_finish_point(\"d\")\n",
    "graph = builder.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "83320227-8ab3-44c0-b6cf-064a7a425b9f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "3f971fa3-29e4-466f-a85e-2863bfecf7fe",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm B to [\"I'm A\"]\n",
      "Adding I'm C to [\"I'm A\"]\n",
      "Adding I'm B2 to [\"I'm A\", \"I'm B\", \"I'm C\"]\n",
      "Adding I'm D to [\"I'm A\", \"I'm B\", \"I'm C\", \"I'm B2\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", \"I'm B\", \"I'm C\", \"I'm B2\", \"I'm D\"]}"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": []})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d45f4477",
   "metadata": {},
   "source": [
    "## Conditional Branching\n",
    "\n",
    "If your fan-out is not deterministic, you can use [add_conditional_edges](https://langchain-ai.github.io/langgraph/reference/graphs/#langgraph.graph.StateGraph.add_conditional_edges) directly.\n",
    "\n",
    "If you have a known \"sink\" node that the conditional branches will route to afterwards, you can provide `then=<final-node-name>` when creating the conditional edges."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "95f5e026",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import Annotated, Sequence\n",
    "\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import END, START, StateGraph\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "    which: str\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_node(\"e\", ReturnNodeValue(\"I'm E\"))\n",
    "\n",
    "\n",
    "def route_bc_or_cd(state: State) -> Sequence[str]:\n",
    "    if state[\"which\"] == \"cd\":\n",
    "        return [\"c\", \"d\"]\n",
    "    return [\"b\", \"c\"]\n",
    "\n",
    "\n",
    "intermediates = [\"b\", \"c\", \"d\"]\n",
    "builder.add_conditional_edges(\n",
    "    \"a\",\n",
    "    route_bc_or_cd,\n",
    "    intermediates,\n",
    ")\n",
    "for node in intermediates:\n",
    "    builder.add_edge(node, \"e\")\n",
    "\n",
    "\n",
    "builder.add_edge(\"e\", END)\n",
    "graph = builder.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "1d0e6c56",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7134f652",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm B to [\"I'm A\"]\n",
      "Adding I'm C to [\"I'm A\"]\n",
      "Adding I'm E to [\"I'm A\", \"I'm B\", \"I'm C\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", \"I'm B\", \"I'm C\", \"I'm E\"], 'which': 'bc'}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": [], \"which\": \"bc\"})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "b130e694",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm D to [\"I'm A\"]\n",
      "Adding I'm C to [\"I'm A\"]\n",
      "Adding I'm E to [\"I'm A\", \"I'm C\", \"I'm D\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", \"I'm C\", \"I'm D\", \"I'm E\"], 'which': 'cd'}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": [], \"which\": \"cd\"})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "952cd6f3",
   "metadata": {},
   "source": [
    "## Stable Sorting\n",
    "\n",
    "When fanned out, nodes are run in parallel as a single \"superstep\". The updates from each superstep are all applied to the state in sequence once the superstep has completed. \n",
    "\n",
    "If you need consistent, predetermined ordering of updates from a parallel superstep, you should write the outputs (along with an identifying key) to a separate field in your state, then combine them in the \"sink\" node by adding regular `edge`'s from each of the fanout nodes to the rendezvous point.\n",
    "\n",
    "For instance, suppose I want to order the outputs of the parallel step by \"reliability\"."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "836bc12d",
   "metadata": {},
   "outputs": [],
   "source": [
    "import operator\n",
    "from typing import Annotated, Sequence\n",
    "\n",
    "from typing_extensions import TypedDict\n",
    "\n",
    "from langgraph.graph import StateGraph\n",
    "\n",
    "\n",
    "def reduce_fanouts(left, right):\n",
    "    if left is None:\n",
    "        left = []\n",
    "    if not right:\n",
    "        # Overwrite\n",
    "        return []\n",
    "    return left + right\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "    fanout_values: Annotated[list, reduce_fanouts]\n",
    "    which: str\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.set_entry_point(\"a\")\n",
    "\n",
    "\n",
    "class ParallelReturnNodeValue:\n",
    "    def __init__(\n",
    "        self,\n",
    "        node_secret: str,\n",
    "        reliability: float,\n",
    "    ):\n",
    "        self._value = node_secret\n",
    "        self._reliability = reliability\n",
    "\n",
    "    def __call__(self, state: State) -> Any:\n",
    "        print(f\"Adding {self._value} to {state['aggregate']} in parallel.\")\n",
    "        return {\n",
    "            \"fanout_values\": [\n",
    "                {\n",
    "                    \"value\": [self._value],\n",
    "                    \"reliability\": self._reliability,\n",
    "                }\n",
    "            ]\n",
    "        }\n",
    "\n",
    "\n",
    "builder.add_node(\"b\", ParallelReturnNodeValue(\"I'm B\", reliability=0.9))\n",
    "\n",
    "builder.add_node(\"c\", ParallelReturnNodeValue(\"I'm C\", reliability=0.1))\n",
    "builder.add_node(\"d\", ParallelReturnNodeValue(\"I'm D\", reliability=0.3))\n",
    "\n",
    "\n",
    "def aggregate_fanout_values(state: State) -> Any:\n",
    "    # Sort by reliability\n",
    "    ranked_values = sorted(\n",
    "        state[\"fanout_values\"], key=lambda x: x[\"reliability\"], reverse=True\n",
    "    )\n",
    "    return {\n",
    "        \"aggregate\": [x[\"value\"] for x in ranked_values] + [\"I'm E\"],\n",
    "        \"fanout_values\": [],\n",
    "    }\n",
    "\n",
    "\n",
    "builder.add_node(\"e\", aggregate_fanout_values)\n",
    "\n",
    "\n",
    "def route_bc_or_cd(state: State) -> Sequence[str]:\n",
    "    if state[\"which\"] == \"cd\":\n",
    "        return [\"c\", \"d\"]\n",
    "    return [\"b\", \"c\"]\n",
    "\n",
    "\n",
    "intermediates = [\"b\", \"c\", \"d\"]\n",
    "builder.add_conditional_edges(\"a\", route_bc_or_cd, intermediates)\n",
    "\n",
    "for node in intermediates:\n",
    "    builder.add_edge(node, \"e\")\n",
    "\n",
    "builder.set_finish_point(\"e\")\n",
    "graph = builder.compile()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "932c497e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": [
       "<IPython.core.display.Image object>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from IPython.display import Image, display\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "933b3afd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm B to [\"I'm A\"] in parallel.\n",
      "Adding I'm C to [\"I'm A\"] in parallel.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", [\"I'm B\"], [\"I'm C\"], \"I'm E\"],\n",
       " 'fanout_values': [],\n",
       " 'which': 'bc'}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": [], \"which\": \"bc\", \"fanout_values\": []})"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "e30531bf",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Adding I'm A to []\n",
      "Adding I'm C to [\"I'm A\"] in parallel.\n",
      "Adding I'm D to [\"I'm A\"] in parallel.\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'aggregate': [\"I'm A\", [\"I'm D\"], [\"I'm C\"], \"I'm E\"],\n",
       " 'fanout_values': [],\n",
       " 'which': 'cd'}"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": [], \"which\": \"cd\"})"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.2"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
